#ifndef __MESIFLAGS_H__
#define __MESIFLAGS_H__

#include "mem/LineFlags.h"
#include <cstdio>

class MESIFlags : public LineFlags {
  private:
    bool shared;

  public:
    // overloaded to force use of CALLOC/FREE
    NEW_DELETE_OPERATORS_INLINE_H(MESIFlags,LineFlags);

    MESIFlags (VA const addr_, uint const blockSize_) 
        : LineFlags(addr_, blockSize_),
          shared(false)
    {
    }

    // Prototype pattern
    virtual LineFlags* newInstance (VA const addr_) const {
        ASSERT(typeid(*this) == typeid(MESIFlags));
        return NEW MESIFlags(addr_, getBlockSize());
    }

    virtual void copyState (LineFlags* _flag) {
        MESIFlags* cloneFlag = CAST_OR_DIE(MESIFlags*, _flag);
        cloneFlag->setShared(this->shared);
        LineFlags::copyState(_flag);
    }
    
    bool isShared () const {
        return shared;
    }

    virtual void setShared (bool const newShared) {
        shared = newShared;
    }

    // MESI:
    // M: valid = 1, dirty = 1, shared = 0
    // E: valid = 1, dirty = 0, shared = 0
    // S: valid = 1, dirty = 0, shared = 1
    // I: valid = 0

  bool is_I(){
    return !isValid();
  }
  bool is_S(){
    //    printf("is_S called!\n");
    return isValid() && isShared();
  }
  bool is_E(){
    //    printf("is_E called!\n");
    return isValid() && !isShared() && !isDirty();
  }
  bool is_M(){
    //    printf("is_M called!\n");
    return isValid() && !isShared() && isDirty();
  }

  void set_I(){
    setValid(false);
    setShared(false);
    setDirty(false);
  }
  void set_S(){
    setValid(true);
    setShared(true);
    setDirty(false);
  }
  void set_E(){
    setValid(true);
    setShared(false);
    setDirty(false);
  }
  void set_M(){
    setValid(true);
    setShared(false);
    setDirty(true);
  }



  protected:
    virtual int appendStrForm(char* buf, int avail) const {
        int n = LineFlags::appendStrForm(buf, avail);
        buf += n;
        avail -= n;
        if (avail <= 0) {
            return n;
        }
        char mesi = !isValid() ? 'I' : isShared() ? 'S' : isDirty() ? 'M' : 'E';
        return n + snprintf(buf, avail, ",S:%d[%c]",
                            (int)shared,
                            mesi);
    }
};
  
#endif // __MESIFLAGS_H__
